package leetcode.tencent;

/**
 * @author Cheng Jun
 * Description: 请你来实现一个 myAtoi(string s) 函数，使其能将字符串转换成一个 32 位有符号整数（类似 C/C++ 中的 atoi 函数）。
 * <p>
 * 函数 myAtoi(string s) 的算法如下：
 * <p>
 * 读入字符串并丢弃无用的前导空格
 * 检查下一个字符（假设还未到字符末尾）为正还是负号，读取该字符（如果有）。 确定最终结果是负数还是正数。 如果两者都不存在，则假定结果为正。
 * 读入下一个字符，直到到达下一个非数字字符或到达输入的结尾。字符串的其余部分将被忽略。
 * 将前面步骤读入的这些数字转换为整数（即，"123" -> 123， "0032" -> 32）。如果没有读入数字，则整数为 0 。必要时更改符号（从步骤 2 开始）。
 * 如果整数数超过 32 位有符号整数范围 [−2^31,  2^31 − 1] ，需要截断这个整数，使其保持在这个范围内。
 * 具体来说，小于 −2^31 的整数应该被固定为 −2^31 ，大于 2^31 − 1 的整数应该被固定为 2^31 − 1 。
 * 返回整数作为最终结果。
 * <p>
 * 来源：力扣（LeetCode）
 * 链接：https://leetcode-cn.com/problems/string-to-integer-atoi
 * 著作权归领扣网络所有。商业转载请联系官方授权，非商业转载请注明出处。
 * <p>
 * 本题中的空白字符只包括空格字符 ' ' 。
 * 除前导空格或数字后的其余字符串外，请勿忽略 任何其他字符。
 * @version 1.0
 * @date 2022/1/22 15:23
 * <p>
 * 二刷 经典题 腾讯面试题 必刷题
 */
public class myAtoi {
    public static void main(String[] args) {
        System.out.println(myAtoi("2147483648"));
    }


    // 思路：
    // 1.先去掉前后的空格；
    // 2.找到一个字符，判断是否 是 数字或 + -
    // 3.for 循环时，注意溢出情况
    static public int myAtoi(String str) {
        // 结果
        int ans = 0;
        // 正负号标识，默认正号
        int sign = 1;
        // 去掉前后的空格
        str = str.trim();
        for (int i = 0; i < str.length(); i++) {
            char curChar = str.charAt(i);
            // 正负号判断
            if (i == 0 && curChar == '+') {
                continue;
            }
            if (i == 0 && curChar == '-') {
                sign = -1;
                continue;
            }
            // 数字的处理逻辑
            if (Character.isDigit(curChar)) {
                int num = curChar - '0';
                if (sign == 1) {
                    // 正数越界
                    if (ans > Integer.MAX_VALUE / 10 || (ans == Integer.MAX_VALUE / 10 && num > Integer.MAX_VALUE % 10)) {
                        return Integer.MAX_VALUE;
                    }
                } else {
                    // 负数越界
                    if (ans < Integer.MIN_VALUE / 10 || (ans == Integer.MIN_VALUE / 10 && -(num) < Integer.MIN_VALUE % 10)) {
                        return Integer.MIN_VALUE;
                    }
                }
                // ans 扩大10倍，注意 num 要乘以 符号标识
                ans = ans * 10 + sign * num;
            } else {
                break;
            }
        }
        return ans;
    }

    // 编程技巧收获：从特殊到一般，先解决特殊情况，然后不断增加 可能的复杂情况，不断优化迭代代码，最后满足所有的情况
    // 比如这题：题目要求实现 字符串转换成一个 32 位有符号整数，算法要求有很多。我们先把要求简单列出来：
    // 1. 前缀空格要去掉
    // 2. 第一个字可能是正负号
    // 3. 当出现 非数字的时候 直接返回 前面的结果
    // 4. 不能超出 int 范围
    // 思路分析：String有实例方法 trim()，可以去掉前后空格
    // 条件2 直接判断 第一个字符是否为正负号
    // 条件3 除了第一个字符 可以为 正负号外，只要碰到非数字的情况，就直接返回前面求到的结果
    // 条件4 不能超出 int 范围，这就要求 在ans 扩大十倍 并加上 (str.charAt(i) -'0') 时不能越界
    static public int myAtoi1(String str) {
        int ans = 0;
        // 条件1
        str = str.trim();
        // 正负号标识
        int sign = 1;
        // 因为 str 被 trim后，长度可能为0，所以建议使用 for循环判断
        for (int i = 0; i < str.length(); i++) {
            char curChar = str.charAt(i);
            // 条件2
            // 细节：注意第一个字符是 加号，也要判断一下。如果不判断，就直接走到数字的判断逻辑中
            if (i == 0 && curChar == '+') {
                continue;
            }
            if (i == 0 && curChar == '-') {
                sign = -1;
                continue;
            }
            // 如果是数字
            if (Character.isDigit(curChar)) {
                // 条件3
                // todo 实现 int越界的判断， 如果不让用 long，就需要注意使用 Integer.MAX_VALUE / 10 和 取模
                ans = ans * 10 + sign * (curChar - '0');
            } else {
                // 条件4
                // 除了第一个字符 可以为 正负号外，只要碰到非数字的情况，就直接返回前面求到的结果
                break;
            }
        }
        return ans;
    }


}
